#include "Texture.h"

#include <FreeImage.h>
#include <memory>

com_ptr<ID3D11ShaderResourceView> LoadTexture(ID3D11Device* device, const std::string& file)
{
	// deleter to use unique ptr on FIBITMAPs
	struct BitmapDeleter 
	{
		void operator()(FIBITMAP *ptr) const
		{
			FreeImage_Unload(ptr);
		}
	};

	// Get file format
	FREE_IMAGE_FORMAT image_format = FreeImage_GetFileType(file.c_str(), 0);
	std::unique_ptr<FIBITMAP, BitmapDeleter> image_bitmap(FreeImage_Load(image_format, file.c_str()));
 
	// note: convertto32bits returns a clone but the original image will be released by the unique_ptr's deleter
	image_bitmap.reset(FreeImage_ConvertTo32Bits(image_bitmap.get()));
	
	FIBITMAP* image_bitmap_raw = image_bitmap.get();

	unsigned int w = FreeImage_GetWidth(image_bitmap_raw);
	unsigned int h = FreeImage_GetHeight(image_bitmap_raw);
 
	//FreeImage loads in BGR format, so you need to swap some bytes
	std::unique_ptr<char[]> textura(new char[w*h*4]);
	char* pixeles = reinterpret_cast<char*>(FreeImage_GetBits(image_bitmap_raw));
 
	for(unsigned int j= 0; j< w*h; j++){
		textura[j*4+0]= pixeles[j*4+2];
		textura[j*4+1]= pixeles[j*4+1];
		textura[j*4+2]= pixeles[j*4+0];
		textura[j*4+3]= pixeles[j*4+3];
	}
 
	// Create texture
    D3D11_TEXTURE2D_DESC desc;
    desc.Width = w;
    desc.Height = h;
    desc.MipLevels = 1;
    desc.ArraySize = 1;
    desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    desc.SampleDesc.Count = 1;
    desc.SampleDesc.Quality = 0;
    desc.Usage = D3D11_USAGE_DEFAULT;
    desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    desc.CPUAccessFlags = 0;
    desc.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA initData;
    initData.pSysMem = textura.get();
    initData.SysMemPitch = w * 4;
    initData.SysMemSlicePitch = 0;

    ID3D11Texture2D* tex_buffer = nullptr;
	HRESULT hr = device->CreateTexture2D(&desc, &initData, &tex_buffer);
	com_ptr<ID3D11Texture2D> tex2d = make_com_ptr(tex_buffer);

	if(FAILED(hr))
	{
		throw std::runtime_error("[Error] Failed to create texture!");
	}

	ID3D11ShaderResourceView* shaderresourceview_buffer;
	hr = device->CreateShaderResourceView(tex2d, NULL, &shaderresourceview_buffer);
	com_ptr<ID3D11ShaderResourceView> shaderresourceview = make_com_ptr(shaderresourceview_buffer);

	if(FAILED(hr))
	{
		throw std::runtime_error("[Error] Failed to create shader resource view!");
	}

	return shaderresourceview;
}